#include<unistd.h>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>

#define COMMAND_SIZE 1024
#define FORMAT "[%s@%s %s]#"

#define MAXARGC 128
char* g_argv[MAXARGC];
int g_argc = 0;

// 重定向
#define NONE_REDIR 0
#define INPUT_REDIR 1
#define OUTPUT_REDIR 2
#define APPEND_REDIR 3

//重定向默认是无重定向
int redir  = NONE_REDIR;
std::string filename;

const char* GetUsr()
{
   char* usr = getenv("USER");
   return usr == NULL ?  "none" : usr; 
}

const char* GetHostName()
{
   char* hostname = getenv("HOSTNAME");
   return hostname == NULL ?  "none" : hostname; 
}

const char* GetPwd()
{
   char* pwd = getenv("PWD");
   return pwd == NULL ?  "none" : pwd; 
}

void MakeCommandline(char cmd_prompt[], int size)
{
    snprintf(cmd_prompt, size, FORMAT,GetUsr(),GetHostName(),GetPwd());
}

const char* GetHome()
{
    const char* home = getenv("HOME");
    return home==NULL?" ":home;
}

void PrintCommandPrompt()
{
    //定义命令行提示符数组
    char prompt[COMMAND_SIZE];
    //获取命令参数
    MakeCommandline(prompt, sizeof(prompt));
    //打印命令行
    printf("%s", prompt);
    //刷新缓冲区
    fflush(stdout);
}

//获取命令行输入
bool GetCommandline(char* out, int size)
{
    //"ls -a -l"
    char* c = fgets(out, size, stdin);
    if(c == NULL) return false;
    //清理\n
    out[strlen(out)-1] = 0; 
    //如果没有输入
    if(strlen(out) == 0) return false;
    //printf("%s\n", out);
    return true;
}


bool  CommandParse(char* commandline)
{
#define SEP " "
    g_argc = 0;
    g_argv[g_argc++] = strtok(commandline,SEP);
    // 命令行分析 "ls -a -l" -> "ls" "-a" "-l"
    //每次分割结果存入g_argv[g_argc]，然后g_argc递增
    while((bool)(g_argv[g_argc++] = strtok(nullptr,SEP))) ;     //strtok持续从上一次分隔符分割的位置分割，直到strtok返回值为null程序结束
    g_argc--;   //删除\n??

    return g_argc>0?true:false;
}

void PrintArgv()
{
    for(int i = 0; g_argv[i]; i++)
    {
        printf("argv[%d]->%s\n", i, g_argv[i]);
    }
    printf("argc: %d\n", g_argc);
}

void RedirCheck(char* cmd)
{
    redir = NONE_REDIR;

    return;
}

bool Cd()
{
    if(g_argc == 1)
    {
        std::string home = GetHome();
        if(home.empty()) return true;
        chdir(home.c_str());
        // return true;
    }
    else
    {
        std::string where = g_argv[1];
        //cd - 或 cd ~
        if(where == "-")
        {
            //todo
        }
        else if(where == "~")
        {
            //todo
        }
        else
        {
            chdir(where.c_str());
            // return true;
        }
    }
    //没有执行到内建命令
    return true;
}

void Echo()
{     
        // echo "hello world"
        // echo $?
        // echo $PATH
}

//内建命令检测
bool CheckAndExecBuiltin()
{
    std::string cmd = g_argv[0];
    if(cmd == "cd") 
    {
        Cd();
        return true;
    }
    else if(cmd == "echo")
    {
        Echo();
        return true;
    }
    else if(cmd == "export")
    {
        //
    }
    else
    {
        //
    }

    return false;
}

//执行命令
int Execute()
{
    //创建子进程
    pid_t id = fork();
    if(id == 0)
    {
        //child

        int fd = -1;
        //子进程检查重定向情况
        if(redir == INPUT_REDIR)
        {
            fd = open(filename.c_str(), O_RDONLY);
            if(fd < 0) exit(1);
            dup2(fd,0);
            close(0);
        }
        else if(redir == OUTPUT_REDIR)
        {
            fd = open(filename.c_str, O_CREAT | O_WONLY | TRUNC, 0666);
            if(df < 0) exit(2);
            dup2(fd, 1);
            close(fd);
        }
        else if(redir == APPEND_REDIR)
        {
            fd = open(filename.c_str, O_CREAT | O_WONLY | APPEND_REDIR, 0666);
            if(fd < 0) exit(2);
            close(fd);
        }
        else{}
        //进程替换
        execvp(g_argv[0], g_argv);
        exit(1);
    }
    
    int status = 0;
    //fater
    pid_t rid = waitpid(id, &status, 0);
    if(rid > 0)
    {
        lastcode = WEXITSTATUS(status);
    }
    return 0;
}

//清空空格
void TrimSpace(char cmd[], int &end)
{
    while(isspace(cmd[end]))
    {
        end++;
    }
}

//内建命令检测
void RediriCheck(char cmd[])
{
    redir = NONE_REDIR;
    filename.clear();
    int start = 0;
    int end = strlen(cmd)-1;

    //ls -a -l >> file.txt > >> <
    while(end > start)      //从后往前检测
    {
        //输入重定向
        if(cmd [end] == '<')
        {
            cmd[end++] = 0;     //将end位置置为0
            TrimSpace(cmd,end);
            redir = INPUT_REDIR;
            filename = cmd + end;
            break;
        }   
        else if(cmd[end] == '>')        
        {
            if(cmd[end-1] == '>')       //追加重定向
            {
                // >>
                cmd[end-1] = 0;
                redir = APPEND_REDIR;
            }
            else                       //输出重定向
            {
                // > 
                redir = OUTPUT_REDIR;
            }
            cmd[end++] = 0;
            TrimSpace(cmd, end);        //清空end后面的所有空格
            filename = cmd + end;       //文件名？
            break;
        }
        else
        {
            end--;
        }
    }

}

int main()
{
    while(1)
    {
         //1.打印命令行提示符
         PrintCommandPrompt();
         sleep(1);
        
         //2.获取用户输入命令
         char commandline[COMMAND_SIZE];
         if(!GetCommandline(commandline,sizeof(commandline)))
            continue;      //获取命令行失败结束

         //3.重定向分析
         RedirCheck(commandline);

         // 4. 命令行分析 "ls -a -l" -> "ls" "-a" "-l"
         if(!CommandParse(commandline))
             continue;
        
         //测试打印命令行
         //PrintArgv();

         //4.检测并执行内建命令
        if(!CheckAndExecBuiltin())
            continue;
         
         //5.执行命令
         Execute();
    }

    return 0;
}
